#include "myshell.h"
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <string>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>

// 命令行参数表，我故意定义成为全局
char *gargv[ARGS] = {NULL};
int gargc = 0;
char pwd[1024]; // 全局变量空间，保存当前shell进程的工作路径
int lastcode = 0;

#define NONE_REDIR 0
#define OUTPUT_REDIR 1
#define APPEND_REDIR 2
#define INPUT_REDIR 3

std::string filename;
int redir_type=NONE_REDIR;

#define TrimSpace(start) do{\
    while(isspace(*start)){\
    start++;\
    }\
}while(0)

void CheckRedir(char cmd[])
{
    char* start=cmd;
    char* end=cmd+strlen(cmd)-1;
    while(start!=end)
    {
        if(*start=='>')
        {
            if(*(start+1)=='>')
            {
                //追加重定向
                redir_type=APPEND_REDIR;
                *start='\0';
                start+=2;
                TrimSpace(start);
                filename=start;
                break;
            }
            else{
             //输出重定向
            redir_type=OUTPUT_REDIR;
             *start='\0';
            start++;
            TrimSpace(start);
            filename=start;
            break;
            }
        }
        else if(*start=='<')
        {
            //输入重定向
            redir_type=INPUT_REDIR;
            *start='\0';
            start++;
            TrimSpace(start);
           filename=start;
            break;
        }
        else{
            start++;
            }
    }
}


void InitGlobal()
{
    gargc=0;
    memset(gargv,0,sizeof(gargv));
}
static std::string GetUsername()
{
    const char* userEnv = getenv("USER");
    std::string username = userEnv ? userEnv : "None";
    return username;
}
static std::string GetHostname()
{
    const char* hostEnv = getenv("HOSTNAME");
    std::string hostname = hostEnv ? hostEnv : "None";
    return hostname;
}
static std::string GetPwd()
{
    // const char* pwdEnv = getenv("PWD");
    // std::string pwd = pwdEnv ? pwdEnv : "None";
    // return pwd;

    char temp[1024];
    getcwd(temp,sizeof(temp));
    snprintf(pwd,sizeof(pwd),"PWD=%s",temp);
    putenv(pwd);

    std::string pwd_lable=temp;
    const std::string pathsep="/";
    auto pos=pwd_lable.rfind(pathsep);
    if(pos==std::string::npos)
    {
        return "None";
    }
    pwd_lable=pwd_lable.substr(pos+pathsep.size());
    return pwd_lable.empty()? "/":pwd_lable;
}
static std::string GetHomePath()
{
    const char* homename = getenv("HOME");
    std::string home = homename ? homename : "/";
    return home;
}

void PrintCommandPrompt()
{
    std::string user = GetUsername();
    std::string hostname = GetHostname();
    std::string pwd = GetPwd();
    printf("%s@%s [%s]#", user.c_str(), hostname.c_str(), pwd.c_str());
}  

bool GetCommandString(char cmd_str_buff[], int len)
{
    if(cmd_str_buff==NULL||len<=0)
    return false;

    char* res=fgets(cmd_str_buff,len,stdin);
    cmd_str_buff[strlen(cmd_str_buff)-1]=0;
    return strlen(cmd_str_buff)==0? false:true;
}


bool ParseCommandString(char cmd[])
{
    if(cmd==NULL)
    return false;
#define SEP " "
    gargv[gargc++]=strtok(cmd,SEP);
    while((bool)(gargv[gargc++]=strtok(NULL,SEP)));
    gargc--;
// #define DeBug
#ifdef DeBug
    printf("--------------------\n");
    for(int i=0;i<gargc;i++)
    {
        printf("gargv[%d]=%s\n",i,gargv[i]);
    }
     printf("--------------------\n");
     for(int i=0;gargv[i];i++)
     {
        printf("gargv[%d]=%s\n",i,gargv[i]);
     }
#endif
    return true; 
}

void ForkAndExec()
{
    pid_t id=fork();
    if(id<0)
    {
        perror("fork");
        return;
    }
    else if(id==0)
    {
        if(redir_type==OUTPUT_REDIR)
        {
            int fd=open(filename.c_str(),O_CREAT | O_WRONLY | O_TRUNC, 0666);
            if(fd<=0)
            {
                perror("无法打开文件");
                exit(1);
            }
            dup2(fd,1);
        }
        else if(redir_type==APPEND_REDIR)
        {
            int fd=open(filename.c_str(), O_WRONLY | O_APPEND, 0666);
            if(fd<=0)
            {
                perror("无法打开文件");
                exit(2);
            }
            dup2(fd,1);
        }
        else if(redir_type==INPUT_REDIR)
        {
            int fd=open(filename.c_str(), O_RDONLY, 0666);
            if(fd<=0)
            {
                perror("无法打开文件");
                exit(3);
            }
            dup2(fd,0);
        }
        else{
            //Nothing
        }
        execvp(gargv[0],gargv);
        exit(0);
    }
    else{
        int status;
        pid_t rid=waitpid(id,&status,0);
        if(rid>0)
        {
            lastcode=WEXITSTATUS(status);
        }
    }
}

bool BuiltInCommandExec()
{
    std::string cmd = gargv[0];
    bool ret=false;
    if(cmd=="cd")
    {
        // build
        if(gargc == 2)
        {
            std::string target = gargv[1];
            if(target == "~")
            {
                ret = true;
                chdir(GetHomePath().c_str());
            }
            else{
                ret = true;
                chdir(gargv[1]);
            }
        }
        else if(gargc == 1)
        {
            ret = true;
            chdir(GetHomePath().c_str());
        }
        else
        {
            //BUG
        }
    }
    else if(cmd=="echo")
    {
        if(gargc==2)
        {
            std::string args=gargv[1];
            if(args[0]=='$')
            {
                if(args[1]=='?')
                {
                    ret=true;
                    printf("lastcode=%d\n",lastcode);
                    lastcode=0;
                }
                else 
                {
                    const char* pargs=&args[1];
                    ret=true;
                    printf("%s\n",getenv(pargs));
                    lastcode=0;
                }
            }
            else 
            {
                ret=true;
                printf("%s\n",args.c_str());
            }
        }
    }
    return ret;
}